package ffu_control_box_sdk

import (
	"fmt"
	"time"

	"github.com/anazh/go-modbus"
	"go.bug.st/serial"
)

// ffu状态
type FFUStatus int

const (
	Open    FFUStatus = 1
	Close   FFUStatus = 2
	Warn    FFUStatus = 3
	Offline FFUStatus = 4
	// 大于100 为风速占比
)

type FFUControlBox struct {
	ModbusAddr int    // modbus地址
	Uart       string // 串口号
	Baud       int    // 波特率
	IsUseTcp   bool   // 是否使用TCP，否则使用串口；需要有对应的信息
	IP         string // IP地址
	Port       int    // 端口号
	client     modbus.Client
}

// 初始化
func NewFFUControlBox(ModbusAddr int, uart string, baud int, isUseTcp bool, ip string, port int) (*FFUControlBox, error) {
	v := &FFUControlBox{
		ModbusAddr: ModbusAddr,
		Uart:       uart,
		Baud:       baud,
		IsUseTcp:   isUseTcp,
		IP:         ip,
		Port:       port,
	}
	if !v.IsUseTcp {
		if v.Uart == "" || v.Baud == 0 {
			return nil, fmt.Errorf("uart is empty")
		}
		srv := modbus.NewRTUClientProvider(modbus.WithSerialConfig(v.Uart,
			serial.Mode{
				BaudRate: baud,
				DataBits: 8,
				StopBits: serial.OneStopBit,
				Parity:   serial.NoParity,
			}))
		srv.TimeOut = 200 * time.Millisecond
		srv.LogMode(false)
		v.client = modbus.NewClient(srv)
		return v, nil
	}
	srv := modbus.NewTCPClientProvider(fmt.Sprintf("%s:%d", v.IP, v.Port))
	srv.LogMode(false)
	v.client = modbus.NewClient(srv)
	return v, nil
}

// 获取串口上的设备数
type FFUInfo struct {
	Uart1FFUNum int
	Uart2FFUNum int
	SpeedUnit   int
	TempUnit    int
	CurrentUint int
	MaxSpeed    int
	MinSpeed    int
}

func (f *FFUControlBox) GetDeviceCount() (info FFUInfo, err error) {
	results, err := f.client.ReadHoldingRegisters(byte(f.ModbusAddr), 0, 8)
	if err != nil {
		return
	}
	if len(results) != 8 {
		err = fmt.Errorf("read input registers error")
		return
	}
	info.Uart1FFUNum = int(results[1])
	info.Uart2FFUNum = int(results[2])
	info.SpeedUnit = int(results[3])
	info.TempUnit = int(results[4])
	info.CurrentUint = int(results[5])
	info.MaxSpeed = int(results[6])
	info.MinSpeed = int(results[7])
	return
}

// 获取设备的状态
// 一次性不要获取过多，避免传输超时
// beginFFU: 从第几个FFU开始；从1开始
// beginFFU+ffuNum <= 200
func (f *FFUControlBox) GetDeviceStatus(isUart1 bool, beginFFU, ffuNum int) ([]FFUStatus, error) {
	beginAddr := 0x0000
	if !isUart1 {
		beginAddr = 0x00c8
	}
	beginAddr = beginAddr + beginFFU - 1
	results, err := f.client.ReadInputRegisters(byte(f.ModbusAddr), uint16(beginAddr), uint16(ffuNum))
	if err != nil {
		return nil, err
	}
	if len(results) != ffuNum {
		return nil, fmt.Errorf("read input registers error")
	}
	status := make([]FFUStatus, ffuNum)
	for i, v := range results {
		if v == 1 {
			status[i] = Open
		} else if v == 2 {
			status[i] = Close
		} else if v == 3 {
			status[i] = Warn
		} else if v > 100 {
			status[i] = FFUStatus(v)
		}
	}
	return status, nil
}

// 获取串口设备的统计状态
type UartStatusCount struct {
	CloseNum   int // 关闭的数量
	LowNum     int // 低风速的数量
	HighNum    int // 高风速的数量
	MiddleNum  int // 中风速的数量
	WarningNum int // 报警的数量
	OfflineNum int // 离线的数量
	OnlineNum  int // 在线的数量
	ErrorNum   int // 错误的数量
}

func (f *FFUControlBox) GetUartStatusCount(isUart1 bool) (status UartStatusCount, err error) {
	beginAddr := 0x0191
	if !isUart1 {
		beginAddr = 0x0198
	}
	results, err := f.client.ReadInputRegisters(byte(f.ModbusAddr), uint16(beginAddr), 7)
	if err != nil {
		return
	}
	if len(results) != 7 {
		err = fmt.Errorf("read input registers error")
		return
	}
	status.CloseNum = int(results[0])
	status.LowNum = int(results[1])
	status.MiddleNum = int(results[2])
	status.HighNum = int(results[3])
	status.WarningNum = int(results[4])
	status.OfflineNum = int(results[5])
	status.OnlineNum = int(results[6])
	return
}

// 获取FFU的温度
// 5. 0x019f~0x0266 串口1设备温度状态 总共200个寄存器
// 6. 0x0267~0x032e 串口2设备温度状态 总共200个寄存器
func (f *FFUControlBox) GetFFUTemp(isUart1 bool, beginFFU, ffuNum int) ([]uint16, error) {
	beginAddr := 0x019f
	if !isUart1 {
		beginAddr = 0x0267
	}
	beginAddr = beginAddr + beginFFU - 1
	results, err := f.client.ReadInputRegisters(byte(f.ModbusAddr), uint16(beginAddr), uint16(ffuNum))
	if err != nil {
		return nil, err
	}
	if len(results) != ffuNum {
		return nil, fmt.Errorf("read input registers error")
	}
	return results, nil
}

// 获取FFU的电流
// 0x032f~0x03f6 串口1设备电流状态 总共200个寄存器
// 0x03f7~0x04be 串口2设备电流状态 总共200个寄存器
func (f *FFUControlBox) GetFFUCurrent(isUart1 bool, beginFFU, ffuNum int) ([]uint16, error) {
	beginAddr := 0x032f
	if !isUart1 {
		beginAddr = 0x03f7
	}
	beginAddr = beginAddr + beginFFU - 1
	results, err := f.client.ReadInputRegisters(byte(f.ModbusAddr), uint16(beginAddr), uint16(ffuNum))
	if err != nil {
		return nil, err
	}
	if len(results) != ffuNum {
		return nil, fmt.Errorf("read input registers error")
	}
	return results, nil
}

// 获取FFU的转速
// 9. 0x04bf~0x0586 串口1设备指令转速状态 总共200个寄存器
// 9. 0x0587~0x064e 串口2设备指令转速状态 总共200个寄存器
func (f *FFUControlBox) GetFFUSpeed(isUart1 bool, beginFFU, ffuNum int) ([]uint16, error) {
	beginAddr := 0x04bf
	if !isUart1 {
		beginAddr = 0x0587
	}
	beginAddr = beginAddr + beginFFU - 1
	results, err := f.client.ReadInputRegisters(byte(f.ModbusAddr), uint16(beginAddr), uint16(ffuNum))
	if err != nil {
		return nil, err
	}
	if len(results) != ffuNum {
		return nil, fmt.Errorf("read input registers error")
	}
	return results, nil
}

// 重启
func (f *FFUControlBox) Restart() error {
	return f.client.WriteSingleCoil(byte(f.ModbusAddr), 0x0000, true)
}

// 设置设备的modbus地址
func (f *FFUControlBox) SetModbusAddr(newAddr int) error {
	return f.client.WriteSingleRegister(byte(f.ModbusAddr), 0, uint16(newAddr))
}

// 设置串口1,2的设备数量
func (f *FFUControlBox) SetDeviceCount(uart1FFUNum, uart2FFUNum int) error {
	err := f.client.WriteSingleRegister(byte(f.ModbusAddr), 0x01, uint16(uart1FFUNum))
	if err != nil {
		return err
	}
	return f.client.WriteSingleRegister(byte(f.ModbusAddr), 0x02, uint16(uart2FFUNum))
}

// ---------------------------------------------------------------
type FfuOrderType int

const (
	CloseOrder FfuOrderType = iota // 关闭
	OpenOrder                      // 打开
	LowSpeed                       // 低速
	MidSpeed                       // 中速
	HighSpeed                      // 高速
	//                            // 设置风速 值等于 100~200 = speed = (100~200-100)%*speedRange-speedLow
)

// 控制一路串口上的所有的设备
func (f *FFUControlBox) ControlUart(isAll, isUart1 bool, orderType FfuOrderType) error {
	beginAddr := 0x0003
	if !isUart1 {
		beginAddr = 0x0004
	}
	if isAll {
		beginAddr = 0x0005
	}
	return f.client.WriteSingleRegister(byte(f.ModbusAddr), uint16(beginAddr), uint16(orderType))
}

// 控制某路串口上的某个FFU
func (f *FFUControlBox) ControlFFU(isUart1 bool, ffuNum int, orderType FfuOrderType) error {
	beginAddr := 01
	if !isUart1 {
		beginAddr = 01
	}
	beginAddr = beginAddr<<8 + ffuNum
	return f.client.WriteSingleRegister(byte(f.ModbusAddr), uint16(beginAddr), uint16(orderType))
}
